package com.sky.aspect;

import com.sky.annotation.AutoFill;
import com.sky.constant.AutoFillConstant;
import com.sky.context.BaseContext;
import com.sky.enumeration.OperationType;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.stereotype.Component;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.time.LocalDateTime;

/**
 * 自定义切面，实现公共字段字段填充
 */
@Aspect
@Component
@Slf4j
public class AutoFillAspect {

    /**
     * 切入点
     */
    @Pointcut("execution(* com.sky.mapper.*.*(..))&& @annotation(com.sky.annotation.AutoFill)")
    public void pointcut() {}

    //应该是前置通知的时候给他赋值

    /**
     * 自定义的前置通知，给公共的字段赋值
     * @param joinPoint
     */
    @Before("pointcut()")
    public void autoFill(JoinPoint joinPoint) {
        log.info("开始进行公共字段的字段填充...");

        //获取当前被拦截的方法上的数据库操作类型，也就是到底是update方法，还是说是insert方法
        // 1. 获取方法签名
        MethodSignature signature = (MethodSignature) joinPoint.getSignature();
        Method method = signature.getMethod();

        // 2. 获取方法上的注解
        AutoFill autoFill = method.getAnnotation(AutoFill.class);
        if (autoFill != null) {
            OperationType opType = autoFill.value();
            log.info("当前方法操作类型: " + opType);

            //获取方法的参数，也就是什么类型的
            Object entity = joinPoint.getArgs()[0];
            if (entity == null) return;

            //准备赋值的语句
            LocalDateTime now = LocalDateTime.now();
            Long currentId = BaseContext.getCurrentId();


            if (opType == OperationType.INSERT) {
                // 这里处理 INSERT 类型逻辑
                //四个字段赋值
                try {
                    Method setCreateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_TIME, LocalDateTime.class);
                    Method setCreateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_CREATE_USER, Long.class);
                    Method setUpdateTime = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_TIME, LocalDateTime.class);
                    Method setUpdateUser = entity.getClass().getDeclaredMethod(AutoFillConstant.SET_UPDATE_USER, Long.class);

                    setCreateTime.invoke(entity,now);
                    setCreateUser.invoke(entity,currentId);
                    setUpdateTime.invoke(entity,now);
                    setUpdateUser.invoke(entity,currentId);
                } catch (NoSuchMethodException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                } catch (InvocationTargetException e) {
                    throw new RuntimeException(e);
                }

            } else if (opType == OperationType.UPDATE) {
                //两个字段赋值
                try {
                    Field updateTime = entity.getClass().getDeclaredField("updateTime");
                    updateTime.setAccessible(true);//反射访问私有字段进行放行
                    updateTime.set(entity, LocalDateTime.now());

                    // updateUser
                    Field updateUser = entity.getClass().getDeclaredField("updateUser");
                    updateUser.setAccessible(true);
                    updateUser.set(entity, BaseContext.getCurrentId());
                    log.info("更新的方法执行成功了！！！");
                } catch (NoSuchFieldException e) {
                    throw new RuntimeException(e);
                } catch (IllegalAccessException e) {
                    throw new RuntimeException(e);
                }
                // 这里处理 UPDATE 类型逻辑
            }

        }


        //1先找到是拦截什么的方法
        //获取当前被拦截的方法的参数--实体对象
        //实体对象的赋值
        //通过反射来进行赋值
    }
}
